package cn.golxen.rsms.service.impl;

import cn.golxen.rsms.bean.bo.*;
import cn.golxen.rsms.bean.entity.*;
import cn.golxen.rsms.bean.vo.*;
import cn.golxen.rsms.commons.utils.CommonsUtils;
import cn.golxen.rsms.commons.utils.LocalDateTimeUtils;
import cn.golxen.rsms.exception.exceptionClass.GetBarcodeInfoException;
import cn.golxen.rsms.redis.GoodsRedis;
import cn.golxen.rsms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BusinessServiceImpl implements BusinessService {
    @Autowired
    LogService logService;
    @Autowired
    GoodsRedis goodsRedis;
    @Autowired
    GoodsService goodsService;
    @Autowired
    StoreService storeService;
    @Autowired
    CustomerService customerService;

    @Override
    public BusinessIncomeVo getBusinessIncomeByHour(BusinessDateBo bo) {
        //获取指定时间的订单日志
        List<PayLog> payLogs = logService.getDonePayLogListByPeriod(bo.getStartDate(), bo.getEndDate(), bo.getStoreId());
        BusinessIncomeVo businessIncomeVo = new BusinessIncomeVo();
        DecimalFormat df = new DecimalFormat("#.00");
        Map<String, Integer> transactionsNumMap = getInitIncomeDetailByHour2();
        Map<String, Double> salesVolumeMap = getInitIncomeDetailByHour();
        Map<String, Double> grossMap = getInitIncomeDetailByHour();
        //对订单日志进行数据处理
        for (PayLog payLog : payLogs) {
            businessIncomeVo.setSalesVolume(businessIncomeVo.getSalesVolume() + payLog.getTotal());
            businessIncomeVo.setTransactionsNum(businessIncomeVo.getTransactionsNum() + 1);
            Double gross = getPayLogGross(payLog);
            businessIncomeVo.setGross(businessIncomeVo.getGross() + gross);

            String hourStr;
            if(payLog.getCreateTime().getHour()<10)
                hourStr = "0"+payLog.getCreateTime().getHour() + ":00";
            else
                hourStr = payLog.getCreateTime().getHour() + ":00";
            transactionsNumMap.merge(hourStr, 1, Integer::sum);
            salesVolumeMap.put(hourStr, Double.valueOf(df.format(salesVolumeMap.get(hourStr) + payLog.getTotal())));
            grossMap.put(hourStr, Double.valueOf(df.format(grossMap.get(hourStr) + gross)));

        }
        //对最终数据进行赋值
        businessIncomeVo.setSalesVolume(Double.valueOf(df.format(businessIncomeVo.getSalesVolume())));
        businessIncomeVo.setGross(Double.valueOf(df.format(businessIncomeVo.getGross())));
        businessIncomeVo.setIncomeDetailByTransactionsNum(transactionsNumMap);
        businessIncomeVo.setIncomeDetailByGross(grossMap);
        businessIncomeVo.setIncomeDetailBySalesVolume(salesVolumeMap);

        return businessIncomeVo;
    }

    @Override
    public BusinessIncomeVo getBusinessIncomeByDays(BusinessDateBo bo) {
        List<PayLog> payLogs = logService.getDonePayLogListByPeriod(bo.getStartDate(), bo.getEndDate(), bo.getStoreId());
        BusinessIncomeVo businessIncomeVo = new BusinessIncomeVo();
        Map<String, Integer> transactionsNumMap = getInitIncomeDetailByDays2(bo);
        Map<String, Double> salesVolumeMap = getInitIncomeDetailByDays(bo);
        Map<String, Double> grossMap = getInitIncomeDetailByDays(bo);
        DecimalFormat df = new DecimalFormat("#.00");
        for (PayLog payLog : payLogs) {
            businessIncomeVo.setSalesVolume(businessIncomeVo.getSalesVolume() + payLog.getTotal());
            businessIncomeVo.setTransactionsNum(businessIncomeVo.getTransactionsNum() + 1);
            Double gross = getPayLogGross(payLog);
            businessIncomeVo.setGross(businessIncomeVo.getGross() + gross);

            String DateStr = payLog.getCreateTime().format(DateTimeFormatter.ofPattern("MM-dd"));
            transactionsNumMap.put(DateStr, transactionsNumMap.get(DateStr) + 1);
            salesVolumeMap.put(DateStr, Double.valueOf(df.format(salesVolumeMap.get(DateStr) + payLog.getTotal())));
            grossMap.put(DateStr, Double.valueOf(df.format(grossMap.get(DateStr) + gross)));
        }

        businessIncomeVo.setSalesVolume(Double.valueOf(df.format(businessIncomeVo.getSalesVolume())));
        businessIncomeVo.setGross(Double.valueOf(df.format(businessIncomeVo.getGross())));
        businessIncomeVo.setIncomeDetailByTransactionsNum(transactionsNumMap);
        businessIncomeVo.setIncomeDetailByGross(grossMap);
        businessIncomeVo.setIncomeDetailBySalesVolume(salesVolumeMap);
        return businessIncomeVo;
    }

    @Override
    public BusinessIncomeVo getBusinessIncome(BusinessDateBo bo) {
        if (ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate()) > 1)
            return getBusinessIncomeByDays(bo);
        else
            return getBusinessIncomeByHour(bo);
    }

    @Override
    public BusinessIncomeReconcileByPaymentVo getBusinessIncomeReconcileByPayment(BusinessDateBo bo) {
        //获取阶段日志
        List<PayLog> payLogs = logService.getDonePayLogListByPeriod(bo.getStartDate(), bo.getEndDate(), bo.getStoreId());
        Map<String, Double> salesVolumeByPayment = new HashMap<>();
        Double total = 0.0;
        DecimalFormat df = new DecimalFormat("#.00");

        double totalAttach = 0.0;
        //遍历并判断支付方式
        for (PayLog payLog : payLogs) {
            if (salesVolumeByPayment.get(payLog.getPayment()) == null)
                salesVolumeByPayment.put(payLog.getPayment(), Double.valueOf(df.format(payLog.getTotal())));
            else {
                salesVolumeByPayment.put(payLog.getPayment(), Double.valueOf(df.format(payLog.getTotal() + salesVolumeByPayment.get(payLog.getPayment()))));
            }
            if (!payLog.getAttach().equals("")) {
                String[] attach = payLog.getAttach().split("\\|");
                //计算优惠成本
                for (String s : attach) {
                    if (!s.equals("")) {
                        totalAttach += Double.parseDouble(s.substring(s.indexOf("=") + 1));
                    }
                }
            }
            total += payLog.getTotal();
        }
        if (salesVolumeByPayment.keySet().size()>0)
            salesVolumeByPayment.put("优惠活动", Double.valueOf(df.format(totalAttach)));
        BusinessIncomeReconcileByPaymentVo vo = new BusinessIncomeReconcileByPaymentVo(salesVolumeByPayment, Double.valueOf(df.format(total)));
        return vo;
    }

    @Override
    public List<BusinessIncomeReconcileByTypeVo> getBusinessIncomeReconcileByType(BusinessDateBo bo) {
        //获取阶段日志
        List<GoodsLog> goodsLogs = logService.getSalesGoodsLogByPeriod(bo);
        Map<String, BusinessIncomeReconcileByTypeVo> typeVoMap = new HashMap<>();
        List<GoodsType> typeList = goodsRedis.getGoodsTypeList();
        DecimalFormat df = new DecimalFormat("#.00");
        long day = ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate());
        LocalDateTime dateTemp = bo.getEndDate().minusDays(day * 3);
        //获取类别的销售数量
        List<GoodsSalesTypeNumBo> goodsSalesTypeNumBoList = logService.getGoodsSalesTypeNumByDay(dateTemp, bo.getEndDate(), bo.getStoreId());
        for (GoodsType type : typeList) {
            typeVoMap.put(type.getGoodsType(), new BusinessIncomeReconcileByTypeVo());
        }
        Double salesVolumeTotal = 0.0;
        for (GoodsLog goodsLog : goodsLogs) {
            GoodsMain goodsMain = new GoodsMain();
            try {
                goodsMain = goodsRedis.getBarcodeInfo(goodsLog.getCode());
            } catch (GetBarcodeInfoException e) {
                goodsMain.setGoodsType("其他");
                if (goodsLog.getCode().length()!=13)
                    goodsMain.setCode("153578456");
                else
                    goodsMain.setCode(goodsLog.getCode());
            }
            //类别基本销售数据处理
            BusinessIncomeReconcileByTypeVo typeVo = typeVoMap.get(goodsMain.getGoodsType());
            typeVo.setGoodsType(goodsMain.getGoodsType());
            if (!typeVo.getJudgeCode().contains(goodsMain.getCode())) {
                typeVo.setRecentSalesTypeNum(typeVo.getRecentSalesTypeNum() + 1);
                typeVo.setJudgeCode(typeVo.getJudgeCode() + goodsMain.getCode());
            }
            Double total = goodsLog.getPrice() * goodsLog.getNum();
            Double gross = total - goodsLog.getCost() * goodsLog.getNum();
            typeVo.setSalesVolume(Double.valueOf(df.format(typeVo.getSalesVolume() + total)));
            typeVo.setGross(Double.valueOf(df.format(typeVo.getGross() + gross)));
            typeVoMap.put(goodsMain.getGoodsType(), typeVo);
            salesVolumeTotal += total;
        }
        //计算销售占比与动销率
        for (GoodsSalesTypeNumBo bo1 : goodsSalesTypeNumBoList) {
            BusinessIncomeReconcileByTypeVo typeVo = typeVoMap.get(bo1.getGoodsType());
            if (typeVo.getGoodsType()==null)
                continue;
            typeVo.setSalesProportion(Double.valueOf(df.format(typeVo.getSalesVolume() / salesVolumeTotal)));
            //动销率=该类近x天有销售的商品数/x*3天该类有售的商品数
            typeVo.setTurnoverRate(Double.valueOf(df.format((double) typeVo.getRecentSalesTypeNum() / bo1.getSalesTypeNum())));
            typeVoMap.put(bo1.getGoodsType(), typeVo);
        }
        List<BusinessIncomeReconcileByTypeVo> res = new LinkedList<>(typeVoMap.values());
        for (int i = 0; i < res.size(); i++) {
            if (res.get(i).getGoodsType() == null) {
                res.remove(res.get(i));
                i--;
            }
        }

        return res;
    }

    @Override
    public List<PayLog> getBusinessSalesFlow(BusinessSalesFlowBo bo) {
        List<PayLog> logs1 = new ArrayList<>(logService.getPayLogListByPeriod(bo));
        List<PayLog> logs2 = new ArrayList<>();
        if (!Objects.equals(bo.getCode(), "")) {
            for (PayLog log : logs1) {
                for (AddOrOutGoodsNumBo bo1 : log.getDetailObject()) {
                    if (bo1.getCode().equals(bo.getCode())) {
                        logs2.add(log);
                        break;
                    }
                }
            }
        } else
            return logs1;
        return logs2;
    }

    @Override
    public BusinessAnalysisReportVo getBusinessAnalysisReport(BusinessDateBo bo) {
        //获取阶段日志
        List<PayLog> logs = logService.getDonePayLogListByPeriod(bo.getStartDate(), bo.getEndDate(), bo.getStoreId());
        BusinessAnalysisReportVo vo = new BusinessAnalysisReportVo();
        Map<String, BusinessAnalysisBaseVo> reportMapTemp = new HashMap<>();
        DecimalFormat df = new DecimalFormat("#.00");
        Double totalSalesVolume = 0.0;
        int totalTransactionsNum = 0;
        //对近35天的日志数据进行处理
        for (PayLog log : logs) {
            String dateStr = log.getCreateTime().format(DateTimeFormatter.ofPattern("MM-dd"));
            BusinessAnalysisBaseVo baseVo = reportMapTemp.get(dateStr);
            if (baseVo == null)
                baseVo = new BusinessAnalysisBaseVo();
            //统计销售额与销售笔数
            baseVo.setSalesVolume(Double.valueOf(df.format(baseVo.getSalesVolume() + log.getTotal())));
            baseVo.setTransactionsNum(baseVo.getTransactionsNum() + 1);

            List<PayLog> logs1 = baseVo.getLogs();
            if (logs1 == null)
                logs1 = new ArrayList<>();
            logs1.add(log);
            baseVo.setLogs(logs1);

            reportMapTemp.put(dateStr, baseVo);
            totalTransactionsNum += 1;
            totalSalesVolume += log.getTotal();

        }
        log.info(bo.getStartDate().format(DateTimeFormatter.ofPattern("MM-dd")));
        String dateFormatTemp="";
        LocalDateTime startDateTemp=bo.getStartDate();
        dateFormatTemp=startDateTemp.format(DateTimeFormatter.ofPattern("MM-dd"));
        //为前端图表初始化x轴数据
        while (!bo.getEndDate().format(DateTimeFormatter.ofPattern("MM-dd")).equals(dateFormatTemp)){
            if (reportMapTemp.get(dateFormatTemp)==null){
                reportMapTemp.put(dateFormatTemp,new BusinessAnalysisBaseVo());
            }
            startDateTemp=startDateTemp.plusDays(1);
            dateFormatTemp=startDateTemp.format(DateTimeFormatter.ofPattern("MM-dd"));
        }
        vo.setTrendChartMap(reportMapTemp);
        int salesTypeNum = 0;
        //计算35天里前七天的销售数据
        for (long i = 7; i >= 1; i--) {
            String dateStr = bo.getEndDate().minusDays(i).format(DateTimeFormatter.ofPattern("MM-dd"));
            if (reportMapTemp.get(dateStr)==null)
                continue;
            if (reportMapTemp.get(dateStr).getSalesVolume() != 0) {
                vo.setSalesVolume(Double.valueOf(df.format(vo.getSalesVolume() + reportMapTemp.get(dateStr).getSalesVolume())));
                vo.setTransactionsNum(vo.getTransactionsNum() + reportMapTemp.get(dateStr).getTransactionsNum());

                for (PayLog log : reportMapTemp.get(dateStr).getLogs()) {
                    for (AddOrOutGoodsNumBo bo1 : log.getDetailObject()) {
                        if (bo1.getCode().length()!=13)
                            continue;
                        if (!vo.getJudgeCode().contains(bo1.getCode())) {
                            salesTypeNum += 1;
                            vo.setJudgeCode(vo.getJudgeCode() + bo1.getCode());
                        }
                    }
                }
            }
        }
        //近七天与前四周均值的差值
        vo.setCompareWithSalesVolume(Double.valueOf(df.format(vo.getSalesVolume() - ((totalSalesVolume - vo.getSalesVolume()) / 4))));
        vo.setCompareWithTransactionsNum(vo.getTransactionsNum() - ((totalTransactionsNum - vo.getTransactionsNum()) / 4));

        LocalDateTime dateTemp = bo.getEndDate().minusDays(21);
        //动销率=该类近x天有销售的商品数/x*3天该类有售的商品数
        List<GoodsSalesTypeNumBo> goodsSalesTypeNumBoList = logService.getGoodsSalesTypeNumByDay(dateTemp, bo.getEndDate(), bo.getStoreId());
        int totalSalesTypeNum = 0;
        for (GoodsSalesTypeNumBo bo1 : goodsSalesTypeNumBoList) {
            totalSalesTypeNum += bo1.getSalesTypeNum();
        }
        vo.setTurnoverRate(Double.valueOf(df.format(((double) salesTypeNum / totalSalesTypeNum))));

        return vo;
    }

    @Override
    public List<BusinessAnalysisReportByGoodsVo> getBusinessAnalysisReportByGoods(BusinessDateBo bo) {
        //获取阶段日志
        List<GoodsLog> goodsLogs = logService.getSalesGoodsLogByPeriod(bo);
        List<BusinessAnalysisReportByGoodsVo> voList = new ArrayList<>();
        Map<String, BusinessAnalysisReportByGoodsVo> reportByGoodsVoMap = new HashMap<>();
        DecimalFormat df = new DecimalFormat("#.00");

        //获取近七天时间段销售数据
        LocalDateTime startDate = bo.getEndDate().minusDays(7);
        for (GoodsLog goodsLog : goodsLogs) {
            if (reportByGoodsVoMap.get(goodsLog.getCode()) != null) {
                BusinessAnalysisReportByGoodsVo reportByGoodsVo = reportByGoodsVoMap.get(goodsLog.getCode());

                reportByGoodsVo.setTotalSalesVolume(Double.valueOf(df.format(reportByGoodsVo.getTotalSalesVolume() + goodsLog.getPrice() * goodsLog.getNum())));
                if (goodsLog.getCreateDate().isAfter(startDate) && goodsLog.getCreateDate().isBefore(bo.getEndDate())
                        || goodsLog.getCreateDate().isEqual(startDate)) {
                    reportByGoodsVo.setSalesVolume(Double.valueOf(df.format(reportByGoodsVo.getSalesVolume() + goodsLog.getPrice() * goodsLog.getNum())));
                    reportByGoodsVo.setSalesNum(reportByGoodsVo.getSalesNum() + goodsLog.getNum());
                }
                reportByGoodsVoMap.put(goodsLog.getCode(), reportByGoodsVo);
            } else if(goodsLog.getCode().length()==13) {
                BusinessAnalysisReportByGoodsVo reportByGoodsVo = new BusinessAnalysisReportByGoodsVo();
                reportByGoodsVo.setTotalSalesVolume(Double.valueOf(df.format(goodsLog.getPrice() * goodsLog.getNum())));
                if (goodsLog.getCreateDate().isAfter(startDate) && goodsLog.getCreateDate().isBefore(bo.getEndDate())
                        || goodsLog.getCreateDate().isEqual(startDate)) {
                    reportByGoodsVo.setSalesNum(goodsLog.getNum());
                    reportByGoodsVo.setSalesVolume(Double.valueOf(df.format(goodsLog.getPrice() * goodsLog.getNum())));
                }
                reportByGoodsVoMap.put(goodsLog.getCode(), reportByGoodsVo);
            }
        }
        List<GoodsMain> goodsMainList = goodsService.getGoodsMainList(new ArrayList<>(reportByGoodsVoMap.keySet()));
        //前四周均值与差值的计算
        for (GoodsMain goodsMain : goodsMainList) {
            BusinessAnalysisReportByGoodsVo reportByGoodsVo = reportByGoodsVoMap.get(goodsMain.getCode());
            BeanUtils.copyProperties(goodsMain, reportByGoodsVo);
            reportByGoodsVo.setBeforeAvgSalesVolume(Double.valueOf(df.format((reportByGoodsVo.getTotalSalesVolume() - reportByGoodsVo.getSalesVolume()) / 4)));
            reportByGoodsVo.setCompareWithSalesVolume(Double.valueOf(df.format(reportByGoodsVo.getSalesVolume() - reportByGoodsVo.getBeforeAvgSalesVolume())));
        }


        return new ArrayList<>(reportByGoodsVoMap.values());
    }

    @Override
    public BusinessBigDataSelectionVo getBusinessBigDataSelection() {
        DecimalFormat df = new DecimalFormat("#.00");
        LocalDateTime endDate = LocalDateTimeUtils.getLocalDateTime();
        LocalDateTime startDate = endDate.minusMonths(6);
        BusinessDateBo businessDateBo = new BusinessDateBo(startDate, endDate, 0);
        //获取近半年订单日志
        List<PayLog> logList = logService.getDonePayLogListByPeriod(businessDateBo.getStartDate(), businessDateBo.getEndDate(), businessDateBo.getStoreId());
        Map<String, Integer> tyingGoodsMap = new HashMap<>();
        //计算顾客喜欢一起买的商品
        for (PayLog payLog : logList) {
            List<AddOrOutGoodsNumBo> numBoList = payLog.getDetailObject();
            if (payLog.getDetailObject().size() > 1) {
                for (AddOrOutGoodsNumBo bo : numBoList) {
                    tyingGoodsMap.merge(bo.getCode(), 1, Integer::sum);
                }
            }
        }
        //获取数据库商品数，计算商品有售的比率与数量以及平均毛利
        int storeCount = storeService.getStoreCountAll();
        List<BusinessBigDataSelectionBo> businessEssentialGoodsBoList = goodsService.getGoodsMainListOnBigDataSelection();
        for (BusinessBigDataSelectionBo goodsBo : businessEssentialGoodsBoList) {
            if (goodsBo.getAvgGross()==null){
                goodsBo.setAvgGross(0.0);
            }
            goodsBo.setAvgGross(Double.valueOf(df.format(goodsBo.getAvgGross())));
            goodsBo.setStoreSalesRate(Double.valueOf(df.format(goodsBo.getStoreSalesNum() / (double) storeCount)));
            if (tyingGoodsMap.get(goodsBo.getCode()) != null)
                goodsBo.setTyingNum(tyingGoodsMap.get(goodsBo.getCode()));
        }

        BusinessBigDataSelectionVo resVo = new BusinessBigDataSelectionVo();
        resVo.setBusinessBigDataSelectionBoList(businessEssentialGoodsBoList);

        for (int i = 0; i < resVo.getBusinessBigDataSelectionBoList().size(); i++) {
            if (resVo.getBusinessBigDataSelectionBoList().get(i).getStoreSalesNum() == 0) {
                resVo.getBusinessBigDataSelectionBoList().remove(resVo.getBusinessBigDataSelectionBoList().get(i));
                i--;
            }
        }

        return resVo;
    }

    @Override
    public Map<String, List<ResGoodsSalesAnalysisVo>> getBusinessSalesRank(BusinessDateBo bo) {
        DecimalFormat df = new DecimalFormat("#.00");
        List<ResGoodsSalesAnalysisVo> voList = goodsService.getGoodsSalesAnalysisByPeriod(bo);
        Map<String, List<ResGoodsSalesAnalysisVo>> voMap = new HashMap<>();
        for (ResGoodsSalesAnalysisVo vo : voList) {
            vo.setSalesVolume(Double.valueOf(df.format(vo.getSalesVolume())));
            vo.setGross(Double.valueOf(df.format(vo.getGross())));
            List<ResGoodsSalesAnalysisVo> voListTemp = new ArrayList<>();
            if (voMap.get(vo.getGoodsType()) != null) {
                voListTemp = voMap.get(vo.getGoodsType());
            }
            voListTemp.add(vo);
            voMap.put(vo.getGoodsType(), voListTemp);
        }
        return voMap;
    }

    @Override
    public List<BusinessPriceAdjustSuggestVo> getBusinessPriceAdjustSuggest(int storeId) {
        DecimalFormat df = new DecimalFormat("#.00");
        List<BusinessPriceAdjustSuggestVo> voList = new ArrayList<>();
        //获取低于建议价的商品
        List<BusinessPriceAdjustSuggestBo> boList = new ArrayList<>(goodsService.getGoodsStoreAndSuggestedPrice(storeId));
        for (BusinessPriceAdjustSuggestBo bo : boList) {
            if (bo.getSuggestedPrice()==null||bo.getSuggestedPrice()==0)
                continue;
            if (bo.getSuggestedPrice() > bo.getPrice()) {
                BusinessPriceAdjustSuggestVo vo = new BusinessPriceAdjustSuggestVo();
                BeanUtils.copyProperties(bo, vo);
                //计算低于多少其他门店和该涨多少元，以及涨了之后的毛利
                vo.setPricingRatio(Double.valueOf(df.format((double) bo.getAbovePriceStoreNum() / bo.getStoreNum())));
                vo.setAdjustSuggest(Double.valueOf(df.format(bo.getSuggestedPrice() - vo.getPrice())));
                vo.setGrossGrowth(Double.valueOf(df.format(vo.getAdjustSuggest() * bo.getSalesNum())));
                voList.add(vo);
            }
        }
        return voList;
    }

    @Override
    public Map<String, CustomerPurchasedAnalysisVo> getCustomerPurchasedAnalysis(BusinessDateBo bo) {
        //获取本店消费过的顾客集合
        Set<String> customerSet = storeService.getCustomer(bo.getStoreId());
        List<CustomerMain> customerMainList = customerService.getCustomerMainList(customerSet);
        Map<String, CustomerPurchasedAnalysisVo> analysisVoMap = new HashMap<>();
        Map<String, CustomerPurchasedAnalysisBo> analysisBoMap = new HashMap<>();
        List<String> codeList = new ArrayList<>();
        //获取在本店消费过顾客的所有购买的商品
        for (CustomerMain customerMain : customerMainList) {
            Map<String, CustomerPurchasedGoodsBo> goodsBoMap = customerMain.getPurchasedGoodsObj();
            for (Map.Entry<String, CustomerPurchasedGoodsBo> entry : goodsBoMap.entrySet()) {
                String storeIdStr = entry.getValue().getStoreIdStr();
                if (storeIdStr.contains(String.valueOf(bo.getStoreId()))) {
                    codeList.add(entry.getKey());
                }
            }
        }
        List<ResGoodsInfoVo> infoVoList = goodsService.getGoodsInfoListByCodeList(codeList, bo.getStoreId());
        Map<String, ResGoodsInfoVo> infoVoMap = infoVoList.stream().collect(Collectors.toMap(ResGoodsInfoVo::getCode, Function.identity()));

        Map<String, Set<String>> typeCustomerTotalMap = new HashMap<>();
        Map<String, Set<String>> typeOutsiderNumMap = new HashMap<>();
        for (CustomerMain customerMain : customerMainList) {
            Map<String, CustomerPurchasedGoodsBo> goodsBoMap = customerMain.getPurchasedGoodsObj();
            //遍历顾客所购买的所有商品
            for (Map.Entry<String, CustomerPurchasedGoodsBo> entry : goodsBoMap.entrySet()) {
                if (entry.getKey().length()!=13)
                    continue;
                ResGoodsInfoVo goodsInfo = infoVoMap.get(entry.getKey());
                if (goodsInfo==null)
                    continue;
                String storeIdStr = entry.getValue().getStoreIdStr();
                //判断是否在本店消费过
                if (storeIdStr.contains(String.valueOf(bo.getStoreId()))) {
                    Set<String> customerTotalSet = typeCustomerTotalMap.get(goodsInfo.getGoodsType());
                    if (customerTotalSet == null)
                        customerTotalSet = new HashSet<>();
                    customerTotalSet.add(customerMain.getCustomerId());
                    typeCustomerTotalMap.put(goodsInfo.getGoodsType(), customerTotalSet);
                    //判断是否只在本店消费
                    if (!storeIdStr.equals(String.valueOf(bo.getStoreId()))) {
                        Set<String> outsiderNumSet = typeOutsiderNumMap.get(goodsInfo.getGoodsType());
                        if (outsiderNumSet == null)
                            outsiderNumSet = new HashSet<>();
                        outsiderNumSet.add(customerMain.getCustomerId());
                        typeOutsiderNumMap.put(goodsInfo.getGoodsType(), outsiderNumSet);
                        CustomerPurchasedAnalysisBo analysisBo = analysisBoMap.get(entry.getKey());
                        if (analysisBo == null) {
                            analysisBo = new CustomerPurchasedAnalysisBo();
                            BeanUtils.copyProperties(goodsInfo, analysisBo);
                        }
                        analysisBo.setOutsiderNum(analysisBo.getOutsiderNum() + 1);
                        analysisBoMap.put(entry.getKey(), analysisBo);
                    }
                }
            }
        }
        List<GoodsMain> goodsMainList = goodsService.getGoodsMainList(codeList);
        Map<String, GoodsMain> goodsMainMap = goodsMainList.stream().collect(Collectors.toMap(GoodsMain::getCode, Function.identity()));
        //遍历在其他店购买过的商品
        for (Map.Entry<String, Set<String>> entry : typeOutsiderNumMap.entrySet()) {
            int customerTotal = typeCustomerTotalMap.get(entry.getKey()).size();
            int outsiderNum = entry.getValue().size();
            Map<String, CustomerPurchasedAnalysisBo> analysisBoMapTemp = new HashMap<>();
            for (Map.Entry<String, CustomerPurchasedAnalysisBo> entry1 : analysisBoMap.entrySet()) {
                CustomerPurchasedAnalysisBo analysisBo = entry1.getValue();
                if (analysisBo.getGoodsType().equals(entry.getKey())) {
                    //判断本店价格是否过高
                    if (goodsMainMap.get(analysisBo.getCode()).getSuggestedPrice() < analysisBo.getPrice())
                        analysisBoMapTemp.put(analysisBo.getCode(), analysisBo);
                }
            }
            CustomerPurchasedAnalysisVo analysisVo = new CustomerPurchasedAnalysisVo(customerTotal, customerTotal - outsiderNum, outsiderNum, analysisBoMapTemp);
            analysisVoMap.put(entry.getKey(), analysisVo);

        }


        return analysisVoMap;
    }

    public Double getPayLogGross(PayLog payLog) {
        double gross = 0.0;
        double costTotal = 0.0;
        List<AddOrOutGoodsNumBo> bos = payLog.getDetailObject();
        for (AddOrOutGoodsNumBo bo : bos) {
            double cost = bo.getCost() * bo.getNum();
//            Double price=bo.getPrice()*bo.getNum();
            costTotal += cost;
        }
        gross = payLog.getTotal() - costTotal;
        return gross;
    }

    public Map<String, Double> getInitIncomeDetailByHour() {
        Map<String, Double> incomeDetail = new HashMap<>();
        int hour = 0;
        while (hour <= 23) {
            String hourStr;
            if (hour < 10)
                hourStr = "0" + hour + ":00";
            else
                hourStr = hour + ":00";
            incomeDetail.put(hourStr, 0.00);
            hour++;
        }

        return incomeDetail;
    }

    public Map<String, Integer> getInitIncomeDetailByHour2() {
        Map<String, Integer> incomeDetail = new HashMap<>();
        int hour = 0;
        while (hour <= 23) {
            String hourStr;
            if (hour < 10)
                hourStr = "0" + hour + ":00";
            else
                hourStr = hour + ":00";
            incomeDetail.put(hourStr, 0);
            hour++;
        }

        return incomeDetail;
    }

    public Map<String, Double> getInitIncomeDetailByDays(BusinessDateBo bo) {
        Map<String, Double> incomeDetail = new HashMap<>();
        long numOfDaysBetween = ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate());
        for (long i = numOfDaysBetween; i >= 1; i--) {
            incomeDetail.put(bo.getEndDate().minusDays(i).format(DateTimeFormatter.ofPattern("MM-dd")), 0.0);
        }

        return incomeDetail;
    }

    public Map<String, Integer> getInitIncomeDetailByDays2(BusinessDateBo bo) {
        Map<String, Integer> incomeDetail = new HashMap<>();
        long numOfDaysBetween = ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate());
        for (long i = numOfDaysBetween; i >= 1; i--) {
            incomeDetail.put(bo.getEndDate().minusDays(i).format(DateTimeFormatter.ofPattern("MM-dd")), 0);
        }

        return incomeDetail;
    }

    public BusinessAnalysisBaseVo getBusinessAnalysisBase(List<PayLog> payLogs, int day) {
        BusinessAnalysisBaseVo businessAnalysisBaseVo = new BusinessAnalysisBaseVo();
        DecimalFormat df = new DecimalFormat("#.00");
        for (PayLog payLog : payLogs) {
            businessAnalysisBaseVo.setSalesVolume(businessAnalysisBaseVo.getSalesVolume() + payLog.getTotal());
            businessAnalysisBaseVo.setTransactionsNum(businessAnalysisBaseVo.getTransactionsNum() + 1);
            Double gross = getPayLogGross(payLog);
            businessAnalysisBaseVo.setGross(businessAnalysisBaseVo.getGross() + gross);

        }
        businessAnalysisBaseVo.setSalesVolume(Double.valueOf(df.format(businessAnalysisBaseVo.getSalesVolume())));
        businessAnalysisBaseVo.setGross(Double.valueOf(df.format(businessAnalysisBaseVo.getGross())));
        return businessAnalysisBaseVo;
    }

}
